Skip to content

FE-1171, FE-1172, FE-1174: fix flaky Playwright tests#8992

Open
claude[bot] wants to merge 19 commits into
mainfrom
claude/fe-1171-fe-1172-fe-1174-flaky-playwright
Open

FE-1171, FE-1172, FE-1174: fix flaky Playwright tests#8992
claude[bot] wants to merge 19 commits into
mainfrom
claude/fe-1171-fe-1172-fe-1174-flaky-playwright

Conversation

@claude

@claude claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Requested by Tim Diekmann · Slack thread

🌟 What is the purpose of this PR?

Fixes the three flaky Playwright failures tracked in FE-1171, FE-1172, and FE-1174. Each one is a race, and each is fixed at the source rather than by retrying the test.

FE-1171 — global-setup sign-in race

Before: the suite's global setup sometimes timed out on waitForURL("/") after clicking Submit on /signin. The signin page fetches its Kratos login flow asynchronously after mount; if setup clicked Submit before the flow response arrived, handleSubmit threw "No sign in flow available" with no retry, so no navigation ever happened and the whole run failed in setup.

After: global setup registers a wait for the /self-service/login flow response before navigating, and awaits it before clicking Submit. The signin page's Submit button is also disabled until the flow has loaded, so Playwright's own actionability checks (and real users) can no longer submit into the void.

FE-1172 — app crash loop from unguarded link-target indexing

Before: specs intermittently found the frontend stuck in an error state on every page. getOutgoingLinkAndTargetEntities / getIncomingLinkAndSourceEntities in @blockprotocol/graph return undefined for rightEntity / leftEntity when the link's has-right-entity / has-left-entity edge isn't resolved into the subgraph, but the LinkEntityAndRightEntity / LinkEntityAndLeftEntity types declared those properties non-optional, with an as cast hiding the mismatch. Consumers indexing rightEntity[0] then crashed with a TypeError — most visibly constructOrg, which runs via the auth context on every page, turning one bad subgraph into an app-wide crash loop. The flakiness trigger is parallel specs acting as the same user: concurrent writes can produce partially-consistent subgraphs in which a link entity is present but its target entity is not.

After: the types are honest — rightEntity / leftEntity are declared possibly undefined — and every consumer the compiler flagged now handles the absence explicitly, split by whether absence is legal:

  • Invariant violation → loud error. Where the query guarantees the target's presence and the entity is public (so permission filtering cannot legitimately remove it), a missing entity means the subgraph itself is inconsistent. Those consumers now throw a descriptive Invariant violation: … error instead of silently skipping: org membership walking in constructOrg (user-and-org.ts), parent-page resolution in use-account-pages.ts, org memberships in the browser plugin's get-user.ts, and syncLinearDataWith web targets in use-linear-integrations.ts. (The billing path in service-usage.ts and the block-contents paths in save.ts / block-collection-contents.ts / org/shared.ts already threw and keep doing so.) The Playwright console fixture fails tests on console errors, so if the server race ever recurs the failure stays loud rather than silently degrading.
  • Legal absence → graceful handling. Where the target can legitimately be absent — entities the user may have lost access to or that were archived (notifications, mention displays/suggestions, the entity editor's incoming/outgoing links tables, claims table) and depth-dependent optional profile data (avatars/bios) — consumers skip gracefully as before.

Behaviour is unchanged when subgraph data is complete. The root cause — subgraph reads not being snapshot-consistent under concurrent writes — is fixed server-side in #8996 (BE-644); this PR deliberately does not silence the error client-side. A changeset is included for @blockprotocol/graph.

FE-1174 — tab-count assertion racing a heavy query

Before: the /types page spec asserted each tab shows a non-zero count (e.g. Entity Types12) with the default 5s expect timeout, but the entity type counts only rendered after the entity types context finished loading every version of every entity type (including archived ones) with deep constraint resolution — a heavy query. Under load the tabs still showed just their title with a spinner at the 5s mark, failing the assertion.

After: the test's default 5s expect timeout is the page's load budget, so the fix is in the page, not the test. The /types page no longer waits on the heavy entity types context for its counts: it runs its own latestOnly: true query with the constraint resolve depths zeroed (only the inheritance chain is needed to classify link types) and classifies link vs non-link types locally. The spec keeps the default expect timeout and the non-zero-count regexes.

Remaining latency risk: test artifacts show navigation + app hydration consume roughly 4s of the budget before any query fires, and the heavy all-versions context query is still triggered in the background by the types table (though it no longer blocks the counts). If the budget is still tight in CI, the next lever is app-shell hydration cost, which is out of scope here.

🔗 Related links

🔍 What does this change?

  • FE-1171tests/hash-playwright/global-setup.ts (await the Kratos login-flow response before clicking Submit), apps/hash-frontend/src/pages/signin.page.tsx (disable Submit until the flow is loaded)
  • FE-1172libs/@blockprotocol/graph/src/types/entity.ts (make rightEntity / leftEntity optional), libs/@blockprotocol/graph/src/stdlib/subgraph/edge/link-entity.ts (document the now-honest return values), plus explicit handling in every consumer the compiler flagged — loud invariant errors where presence is guaranteed (apps/hash-frontend/src/lib/user-and-org.ts, apps/hash-frontend/src/components/hooks/use-account-pages.ts, use-linear-integrations.ts, apps/plugin-browser/src/shared/get-user.ts), graceful skips where absence is legal: notifications-with-links-context.tsx, block-collection-contents.ts, block-select-data-modal.tsx, mention-display.tsx, mention-suggester.tsx, claims-table.tsx, entity-editor links-section (incoming-links-section.tsx, incoming-links-table.tsx, readonly-outgoing-links-table.tsx, use-rows.ts), get-entity-multi-type-dependencies.ts, use-flow-runs-usage.ts, apps/hash-api/src/graphql/resolvers/knowledge/org/shared.ts, apps/plugin-browser/src/shared/get-user.ts, libs/@local/hash-isomorphic-utils/src/save.ts, libs/@local/hash-isomorphic-utils/src/service-usage.ts; changeset in .changeset/fe-1172-optional-link-targets.md
  • FE-1174apps/hash-frontend/src/pages/types/[[...type-kind]].page.tsx (page-scoped latestOnly entity types query with narrowed resolve depths, replacing the page's dependence on the heavy all-versions entity types context), tests/hash-playwright/tests/features/types-page.spec.ts (default expect timeout kept — the 5s budget is the point of the test)

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Sites that construct LinkEntityAndRightEntity-shaped values with their own explicit generic instantiations (e.g. save.ts, block-collection-contents.ts) still assert non-optional target arrays; the compiler accepts these and their existing runtime guards were left as-is.

🐾 Next steps

  • Known follow-up (not fixed here): the hard-coded sleep(500) in the tests/hash-playwright/tests/features/entity-editing.spec.ts helpers is the same class of bug — a fixed delay racing async rendering — and should be replaced with a condition-based wait.

🛡 What tests cover this?

  • The existing Playwright suite (global-setup.ts, types-page.spec.ts) exercises FE-1171 and FE-1174 directly; the types-page spec now enforces the 5s load budget with the default expect timeout.
  • The Playwright console fixture fails any test on console errors, so the new FE-1172 invariant errors keep the flake loud if the server race recurs before BE-644: Run subgraph reads in a single READ ONLY, REPEATABLE READ transaction #8996 lands.
  • tests/hash-backend-integration/src/tests/subgraph/friendship.test.ts already asserts rightEntity: undefined / rightEntity: [] for unresolved and archived targets, which the FE-1172 type change now reflects honestly.
  • Typecheck (lint:tsc) passes for @blockprotocol/graph, @local/hash-isomorphic-utils, @local/hash-backend-utils, @apps/hash-frontend, @apps/hash-api, @apps/plugin-browser, @tests/hash-playwright, and @tests/hash-backend-integration; eslint and oxfmt clean on changed files.

❓ How to test this?

  1. Checkout the branch
  2. Run the Playwright suite repeatedly (or CI several times) — global setup should never fail on sign-in, and the types-page tab counts should render within the default 5s expect timeout
  3. To reproduce the FE-1172 class: render a page whose subgraph contains a membership (or other presence-guaranteed) link without its resolved target — the app should fail loudly with a descriptive Invariant violation … error (the read inconsistency itself is fixed in BE-644: Run subgraph reads in a single READ ONLY, REPEATABLE READ transaction #8996) rather than silently rendering incomplete data; genuinely-optional targets (notifications, links tables, mentions) are still skipped gracefully

📹 Demo

N/A — test-stability and defensive-typing changes with no intended UI change (the signin Submit button is now briefly disabled while the login flow loads).

🤖 Generated with Claude Code

https://claude.ai/code/session_01VQLxSZtnPp3HfxFycFLwLY


Generated by Claude Code

claude added 3 commits July 9, 2026 13:49
The signin page fetches its Kratos login flow asynchronously after mount,
and submitting before the flow has loaded throws without retrying, so the
test's waitForURL never resolves.

- global-setup: wait for the /self-service/login flow response (registered
  before page.goto so it can't be missed) before clicking Submit
- signin page: disable the Submit button until the flow has loaded, so
  Playwright's actionability checks also cover this

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQLxSZtnPp3HfxFycFLwLY
…1174)

The tab counts only render once the types contexts finish loading all
types (a heavy all-versions query); until then the tabs show just their
title with a spinner. The default 5s expect timeout races that query –
give each tab-count assertion an explicit 30s timeout instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQLxSZtnPp3HfxFycFLwLY
getOutgoingLinkAndTargetEntities / getIncomingLinkAndSourceEntities
return `undefined` for rightEntity / leftEntity when the link's
has-right-entity / has-left-entity edge is not resolved into the
subgraph, but LinkEntityAndRightEntity / LinkEntityAndLeftEntity
declared those properties as non-optional and an `as` cast hid the
mismatch. Consumers indexing `rightEntity[0]` then crash at runtime –
most visibly constructOrg, which runs via the auth context on every
page and turned a partially-consistent subgraph into an app-wide
crash loop.

- declare rightEntity / leftEntity as possibly undefined
- guard every consumer flagged by the compiler, skipping links whose
  target/source entity array is missing or empty instead of throwing
- add a changeset for @blockprotocol/graph

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQLxSZtnPp3HfxFycFLwLY
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview, Comment Jul 16, 2026 1:43pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Jul 16, 2026 1:43pm
petrinaut Skipped Skipped Comment Jul 16, 2026 1:43pm

@github-actions github-actions Bot added area/apps > hash* Affects HASH (a `hash-*` app) area/infra Relates to version control, CI, CD or IaC (area) area/apps > hash-api Affects the HASH API (app) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team area/tests New or updated tests area/tests > playwright New or updated Playwright tests area/apps labels Jul 9, 2026
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.56%. Comparing base (c2d06c8) to head (b91ae5c).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
libs/@local/hash-isomorphic-utils/src/save.ts 0.00% 15 Missing ⚠️
...-api/src/graphql/resolvers/knowledge/org/shared.ts 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8992      +/-   ##
==========================================
+ Coverage   59.35%   59.56%   +0.20%     
==========================================
  Files        1373     1387      +14     
  Lines      134439   136035    +1596     
  Branches     6066     6185     +119     
==========================================
+ Hits        79797    81025    +1228     
- Misses      53710    54070     +360     
- Partials      932      940       +8     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.92% <ø> (+0.53%) ⬆️
apps.hash-api 7.59% <0.00%> (+1.19%) ⬆️
local.hash-backend-utils 1.88% <ø> (-0.03%) ⬇️
local.hash-isomorphic-utils 0.17% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

claude added 2 commits July 10, 2026 10:50
…tities (FE-1172)

Where a link's target is a public entity whose presence in the subgraph
is guaranteed by the query (user/org membership targets, parent pages,
linear-sync web targets), a missing entity now throws a descriptive
error referencing BE-644 instead of being silently skipped. The root
cause (subgraph reads not being snapshot-consistent) is being fixed
server-side; these errors keep the invariant violation loud if it ever
recurs. Genuinely-optional absences (notifications, mentions, links
tables, permission-filterable targets) remain graceful.
…ng test timeout (FE-1174)

The /types page previously derived its entity type tab counts from the
entity types context, which fetches every version of every entity type
(including archived ones) with deep constraint resolution - a heavy
query that could take longer than the Playwright default expect timeout
to resolve. The page now runs its own latestOnly query with constraint
resolve depths zeroed (only the inheritance chain is needed to classify
link types), and classifies link vs non-link types locally.

The 30s expect timeout previously added to the types-page spec is
reverted: the default 5s timeout is the page's load budget.
Comment thread apps/hash-frontend/src/components/hooks/use-account-pages.ts Outdated
Comment thread apps/hash-frontend/src/lib/user-and-org.ts Outdated
…variables

Remove ticket references from invariant-error messages and comments -
the errors describe what is wrong, not which ticket tracks it. In
constructUser, collect the checked link/target entity revisions instead
of re-indexing the revision arrays with non-null assertions afterwards.
TimDiekmann
TimDiekmann previously approved these changes Jul 10, 2026
@TimDiekmann
TimDiekmann marked this pull request as ready for review July 10, 2026 11:41
@TimDiekmann
TimDiekmann requested review from CiaranMn and Copilot July 10, 2026 11:41
Move the linkEntityTypeIds registration after the missing source/target
guard in the incoming and outgoing links tables, so a skipped link no
longer causes a custom column to render for a link type with no visible
rows.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 10:52 Inactive
Comment thread apps/plugin-browser/src/shared/get-user.ts
Wherever a filter, find, or guard has already established that a link
or target entity revision is present, bind it to a variable and use
that instead of re-indexing the array with optional chaining or a
non-null assertion:

- get-user: collect org memberships and browser-settings targets via
  flatMap so the checked revisions carry through to their consumers
- use-account-pages: carry the checked has-parent link revision
  through to the invariant error instead of re-indexing
- use-flow-runs-usage, service-usage: destructure the single link
  before the exactly-one guard rather than asserting [0]! after it
- save, block-collection-contents: bind the link revision inside the
  has-data find predicates
- org invitations resolver, claims-table: bind the checked link and
  reuse it in the following clauses
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 11:16 Inactive
Comment thread apps/plugin-browser/src/shared/get-user.ts
A present link whose target entity is missing from the subgraph must not
look like 'no link', or the code creates a duplicate entity and link.

- get-user.ts: the me query pairs incoming has-left-entity with outgoing
  has-right-entity hops and the settings entity is the user's own entity
  in their own web, so an unresolved target is an invariant violation –
  throw instead of falling through to create a duplicate settings entity.
- block-select-data-modal.tsx: the query entity may live in a different
  web to the block, so the viewer may see the has-query link without its
  target. Track the link separately, show an explanatory message instead
  of the editor in that state, and guard the create path against it.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 11:27 Inactive
Comment thread apps/hash-frontend/src/components/hooks/use-account-pages.ts Outdated
A has-parent link can be present in the account-pages subgraph while its
target has no revisions there: metadata archival closes the entity's
decision-time interval so it no longer overlaps the queried interval, and
a target hidden from the requester is likewise absent. The stdlib then
returns an empty rightEntity array for the resolved edge, so absence is a
legal state rather than a malformed subgraph. Restore graceful parentless
handling instead of throwing, and document the present-but-empty case on
the LinkEntityAndRightEntity/LeftEntity types.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 11:38 Inactive
Comment thread apps/plugin-browser/src/shared/get-user.ts
Comment thread apps/hash-frontend/src/components/hooks/use-account-pages.ts
…y has no visible revisions; drop unused parent-link binding
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 11:46 Inactive
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

PR Review Summary (re-run)

Re-run of the earlier pr-review-toolkit review (which ran at head 79e6816), now against head 3e7942f — covering the full diff vs main with all six aspects (code, tests, comments, errors, types, simplify), with focus on the eight commits landed since (2ae56ff3e7942f).

Status of previous run's findings

  • /types page silent error handling — RESOLVED (2ae56ff): errors is now logged when the subgraph is absent, and the effect's promise gets a .catch (types/[[...type-kind]].page.tsx:89-93, 121-126).
  • Notifications throwing on absent link targets — RESOLVED (2ae56ff): mention/comment branches now return null, filtered out before sorting — verified type-safe end to end.
  • Simplifier suggestions (flatMap/bind cleanups) — ADDRESSED (53dcc36, 3e7942f).
  • Test suggestions — partially superseded: the use-account-pages invariant throw they targeted was deliberately reverted in a5b20ea.

Critical Issues (0 found)

None.

Important Issues (3 found — all NEW)

  • [silent-failure-hunter] The plugin's new "surface loudly" invariant errors can never be heard: the getUser promise chain ends in a pre-existing bare .catch(() => null) [apps/plugin-browser/src/shared/get-user.ts:311]. The two new invariant throws (unresolved right-entity edge :115-127; missing org entity :266-276) and any failure of the new settings-recreation path (createEntity calls — a partial failure can create the entity but never link it) are all silently converted to null, which callers treat as "signed out" (and background.ts clears local storage). No log, no Sentry. The catch predates this PR, but the PR's error-handling strategy in this file depends on propagation that doesn't exist. Fix is small: log (and report) the error before returning null.
  • [code-reviewer] (confidence 82) Two call sites bypass the new optional typing via caller-supplied generics that re-assert rightEntity as required, laundered through the stdlib's as LinkAndRightEntities cast: [libs/@local/hash-isomorphic-utils/src/save.ts:538-545] and [apps/hash-frontend/src/pages/shared/block-collection-contents.ts:131-138]. In block-collection-contents.ts the filter checks only linkEntity, then rightEntityRevisions[0]! feeds .properties (:158-161) — a TypeError crash on exactly the legal-absence case this PR documents (empty array when the target is archived/invisible — pinned by friendship.test.ts:1122-1128). These lines are inherited from main, but they sit squarely inside FE-1172's "audit all consumers" scope and are the same unsafe-cast pattern the changeset describes removing. Fix: use LinkEntityAndRightEntity<HashEntity<Block>, ...>[] (as org/shared.ts:61-63 correctly does) and let the compiler force handling.
  • [silent-failure-hunter] The new graceful skip of notifications leaves a permanent, undiagnosable badge mismatch: skipped notifications produce no signal at all (not even console.warn), while the app-wide unread badge counts root entities independently of link resolution (summarizeEntities.count, [apps/hash-frontend/src/shared/notification-count-context.tsx:317-318]) — badge says 3, list shows 2, forever. Data-corruption absence is also now indistinguishable from permission-based absence. Suggested: keep the skip, add a console.warn naming the entity and missing link(s); the graph-change branch's existing auto-archive @todo would fix the badge as a follow-up.

Suggestions (10 found)

  • [silent-failure-hunter] (NEW) Settings recreation in get-user.ts:131-139 happens silently and never archives the dangling has link; a permissions regression (not just archival) also lands here and forks state. Warn when recovering, and archive the dead link.
  • [silent-failure-hunter] (NEW) Other new graceful skips emit zero diagnostics where a warn would help: pages silently re-filed as sidebar roots [use-account-pages.ts:73-89], dashboard items vanishing [dashboard/[dashboard-id].page.tsx:233-239], and usage records silently excluded from cost totals [use-flow-runs-usage.ts:139-143] — the last is inconsistent with its own sibling (wrong link count throws, missing link target silently under-reports costs).
  • [silent-failure-hunter] (NEW) block-select-data-modal.tsx: the duplicate-query guard throw (:162-167) rejects into EntityQueryEditor.onSubmitSave, which has try/finally with no catch — an unhandled rejection; and while blockSubgraph is still loading the memo yields {undefined, undefined}, so a fast save bypasses the guard it exists for. Consider disabling save until the subgraph is present, and catching save rejections.
  • [silent-failure-hunter] (UNCHANGED sites, touched by this PR) Misleading/vague invariant messages: org/shared.ts:88-92 says "is not linked to anything" when the link exists but its org entity is absent; block-collection-contents.ts:176 throws generic "Error fetching block data" where the sibling in save.ts:468-472 includes the entityId.
  • [comment-analyzer] (NEW) use-account-pages.ts:82-88: the "parent page may be archived (its revisions no longer overlap the queried interval)" example is dubious — pages archive via the archived property (use-archive-page.ts:50), which keeps revisions in the subgraph; only entity-level archival ends the interval. Lead with the permission/visibility case. Same file: "legitimately absent (rightEntity missing or empty)" lumps undefined (unresolved edge = inconsistency, which get-user.ts throws on for the same query shape) in with legitimate absence.
  • [comment-analyzer] (NEW) The three "X entities are public — if the link is in the subgraph, its target must be too" invariant comments (get-user.ts:268-272, user-and-org.ts:96-101, use-linear-integrations.ts:349-354) are in tension with this PR's own JSDoc: public visibility rules out the permission case but not the archived case. Related — [pr-test-analyzer] (criticality 5/10): constructOrg throws on leftEntity?.[0] falsy, which includes the empty-array (archived member) case, so an org with one entity-archived member crashes the whole org page; a small fixture test would pin whether that's intended [user-and-org.ts:276-289].
  • [pr-test-analyzer] (NEW, 5-6/10) The new decision branches from the last 8 commits have no unit coverage, though the tri-state stdlib contract itself is pinned by friendship.test.ts (integration): the get-user.ts throw/recreate/use tri-state, the block-select-data-modal link-vs-target derivation (its duplicate-prevention rationale), and the use-account-pages parentless fallback are each one extraction away from a vitest-able pure function.
  • [pr-test-analyzer] (UNCHANGED) types-page.spec.ts:23-26 asserts only non-zero counts, so it cannot catch the regression class FE-1174 guards against (dropping latestOnly, or link/non-link classification degenerating). Asserting tab count == rendered rows would pin both. Also minor: signin-utils.ts:15-18 has the identical goto/fill/click sequence protected only by the app-side disabled={!flow} — worth a comment or the same waitForResponse.
  • [type-design-analyzer] (NEW) block-select-data-modal's { existingQueryLinkEntity, existingQuery } pair makes the illegal state query && !link representable; a tiny discriminated union would make the render/save branches exhaustive — optional at current size. Core entity.ts types rated: expression 7/10, usefulness 9/10, enforcement 5/10 — the deduction is the pre-existing, @todo-flagged caller-generic cast escape hatch in link-entity.ts:345/406, which is exactly what the code-reviewer finding above exploits.
  • [code-simplifier] (NEW) The !x || xs.length !== 1 guards in use-flow-runs-usage.ts:128-139 and service-usage.ts:44-63 read as a second failure mode that doesn't exist (the extra term is only TS narrowing); if (xs.length !== 1) throw + xs[0]?.rightEntity?.[0] is equivalent and cleaner since both sites already handle undefined next. Also use-account-pages.ts:73-89: the flatMap builds [{ rightEntity }] and uses nothing else — a plain find says the same thing.

Strengths

  • Both Important findings from the previous run were fixed properly, not papered over, and the fixes verified clean end to end.
  • [comment-analyzer]/[type-design-analyzer] The revised entity.ts JSDoc now precisely matches stdlib behavior (undefined = unresolved edge, [] = no visible revisions — verified against link-entity.ts and pinned by friendship.test.ts), and two consumers put the distinction to correctness-bearing use (duplicate-creation prevention in get-user.ts and the block modal). The get-user.ts invariant comment's claim about the me query's traversal paths was verified against the actual resolver.
  • [code-reviewer] Exhaustive check of all 26 traversal call sites found the FE-1172 consumer audit otherwise complete; FE-1171 (waitForResponse registered before goto, disabled={!flow}) and FE-1174 (inheritsFrom depth 255 confirmed) verified clean.
  • The incremental commits show genuine per-site triage rather than mechanical ?. insertion: a1a48d7 fixed phantom filter-dropdown entries for skipped rows, a5b20ea correctly retracted a wrong invariant, and the block modal's red "query could not be loaded" message is the best user-facing error feedback in the PR.

Recommended Action

  1. Add logging/reporting to the getUser catch — one small change that makes all the PR's new invariants observable.
  2. Fix the two required-rightEntity caller generics (or at minimum guard block-collection-contents.ts:158).
  3. Add console.warn to the notification skip (badge mismatch) and ideally the other new silent-skip sites.
  4. Treat the comment precision fixes, unit-test extractions, and simplifier cleanups as optional follow-ups.

…tity caller generics in block collection consumers, and warn when notifications are skipped over unresolved links
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 13:02 Inactive
@claude

claude Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

The three Important findings from the review re-run are addressed in 7240cc3:

  • Silenced invariant errors in the plugin's getUser: the bare .catch(() => null) in apps/plugin-browser/src/shared/get-user.ts now logs the error via console.error before returning null, so invariant violations and settings-recreation failures are observable instead of presenting as "signed out".
  • Required-rightEntity caller generics: save.ts and block-collection-contents.ts now pass optional-rightEntity LinkEntityAndRightEntity generics and bind the checked link/target once via flatMap; the rightEntityRevisions[0]! crash site in block-collection-contents.ts now gracefully skips a content link whose target block has no visible revisions (legal absence — blocks are not public, so archival/permission loss cannot be ruled out).
  • Silent notification skip: the mention/comment return null branches in notifications-with-links-context.tsx now emit a console.warn naming the notification entityId and the specific link(s) whose targets could not be resolved, keeping the skip behavior.

Comment thread libs/@local/hash-isomorphic-utils/src/save.ts
…, and tolerate the notification-skip warnings in the Playwright console fixture
@vercel
vercel Bot temporarily deployed to Preview – petrinaut July 16, 2026 13:14 Inactive

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 275ecbf. Configure here.

Comment thread libs/@local/hash-isomorphic-utils/src/save.ts
…, and instead fail the save only when a persisted block in the document is missing from the fetched block list
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps > hash-api Affects the HASH API (app) area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests > playwright New or updated Playwright tests area/tests New or updated tests type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants